]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
iconGrid: Create icon clones in a separate loop
authorDaniel van Vugt <daniel.van.vugt@canonical.com>
Fri, 14 Feb 2020 10:24:58 +0000 (18:24 +0800)
committerFlorian Müllner <florian.muellner@gmail.com>
Wed, 19 Feb 2020 15:39:21 +0000 (15:39 +0000)
For reasons not yet fully understood, `Main.uiGroup.add_actor` takes around
10 milliseconds to complete.

Because of this, each `actor.opacity = 0` has a good chance of falling
on a different frame. And when it does, `_opacityChangedId` also lands
on multiple different frames each incurring a separate relayout cycle.
It is this excessive number of relayouts that causes stuttering in the
icon grid animation (#2065). But it is the slowness of `uiGroup.add_actor`
that causes the number to be excessive when it should be one.

By creating the clones and adding them to `uiGroup` early, we then enable
the existing loop starting the animation to complete within a single frame.
And by completing within a single frame all the opacity changes land within
the same frame interval, thus incurring only a single relayout instead of
many.

This issue went unnoticed until 004a5e1042 (!704), after which the slow
emissions of `notify::opacity` became a more visible performance problem.

Closes: https://gitlab.gnome.org/GNOME/gnome-shell/issues/2065
https://gitlab.gnome.org/GNOME/gnome-shell/merge_requests/1002

js/ui/iconGrid.js

index 19d019f4db5e2d334373ae8f3f69d82927060d3b..25cd1409927a929554610af3b54bb3764d4b8e86 100644 (file)
@@ -556,15 +556,25 @@ var IconGrid = GObject.registerClass({
         }, Infinity);
         let normalization = maxDist - minDist;
 
-        for (let index = 0; index < actors.length; index++) {
-            let actor = actors[index];
+        actors.forEach(actor => {
+            let clone = new Clutter.Clone({ source: actor });
+            this._clonesAnimating.push(clone);
+            Main.uiGroup.add_actor(clone);
+        });
+
+        /*
+         * ^
+         * | These need to be separate loops because Main.uiGroup.add_actor
+         * | is excessively slow if done inside the below loop and we want the
+         * | below loop to complete within one frame interval (#2065, !1002).
+         * v
+         */
+
+        this._clonesAnimating.forEach(actorClone => {
+            let actor = actorClone.source;
             actor.opacity = 0;
             actor.reactive = false;
 
-            let actorClone = new Clutter.Clone({ source: actor });
-            this._clonesAnimating.push(actorClone);
-            Main.uiGroup.add_actor(actorClone);
-
             let [width, height] = this._getAllocatedChildSizeAndSpacing(actor);
             actorClone.set_size(width, height);
             let scaleX = sourceScaledWidth / width;
@@ -631,7 +641,7 @@ var IconGrid = GObject.registerClass({
 
             actorClone.ease(movementParams);
             actorClone.ease(fadeParams);
-        }
+        });
     }
 
     _getAllocatedChildSizeAndSpacing(child) {